#include "leos_timer.h"

LE_LIST_HEAD_INIT(sys_timer_list);

static void le_timer_remove(le_timer_t timer)
{
    LE_TIMER_ENTER_CRITICAL;

    le_list_remove(&timer->list);
    timer->flag = LE_TIMER_FLAG_STOP;

    LE_TIMER_EXIT_CRITICAL;
}

void le_timer_init(le_timer_t timer, 
                   void (*timeout_cb)(void *parameter),
                   void *parameter)
{
    timer->flag         = LE_TIMER_FLAG_STOP;

    timer->timeout_tick = 0;

    timer->timeout_cb   = timeout_cb;
    timer->parameter    = parameter;

    le_list_init(&timer->list);
}

void le_timer_start(le_timer_t timer, le_tick_t timeout_tick)
{
    le_list_t *pos = &sys_timer_list;

    LE_TIMER_ENTER_CRITICAL;

    le_timer_remove(timer);

    timer->timeout_tick = timeout_tick;
    timer->flag         = LE_TIMER_FLAG_ACTIVE;

    le_list_for_each(node, &sys_timer_list) {
        le_timer_t p = le_container_of(node, struct le_timer, list);
        if (timeout_tick < p->timeout_tick) {
            pos = &p->list;
            break;
        }
    }

    le_list_insert_before(&timer->list, pos);

    LE_TIMER_EXIT_CRITICAL;
}

void le_timer_stop(le_timer_t timer)
{
    le_timer_remove(timer);
}

void le_timer_check(le_tick_t current_tick)
{
    le_list_for_each_safe(node, &sys_timer_list) {
        le_timer_t p = le_container_of(node, struct le_timer, list);
        if (current_tick < p->timeout_tick) {
            break;
        }

        le_timer_remove(p);

        if (p->timeout_cb) {
            p->timeout_cb(p->parameter);
        }
    }
}
